package com.breeze.components.core.enums;

import cn.hutool.core.util.StrUtil;
import com.breeze.components.core.exception.ApiException;
import com.breeze.components.core.exception.error.ErrorCode;
import com.breeze.components.core.exception.error.ErrorCodeInterface;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Predicate;

/**
 * 通用枚举接口
 *
 * @author breeze
 */
public interface EnumInterface {

  /**
   * 解析枚举值 返回枚举
   *
   * @param enumClass 枚举类
   * @param code 枚举码
   * @param <T> 类型
   * @return 解析枚举值 返回枚举
   */
  static <T extends Enum<T> & EnumInterface> T fromCodeThrow(Class<T> enumClass, Integer code) {
    return fromCodeThrow(enumClass, code, ErrorCode.Business.COMMON_UNSUPPORTED_OPERATION);
  }

  /**
   * 解析枚举值 返回枚举
   *
   * @param enumClass 枚举类
   * @param code 枚举码
   * @param other 其他
   * @param <T> 类型
   * @return 解析枚举值 返回枚举
   */
  static <T extends Enum<T> & EnumInterface> T fromCodeElse(
      Class<T> enumClass, Integer code, T other) {
    return fromPredicateElse(enumClass, codePredicate(code), other);
  }

  /**
   * 解析枚举值 返回枚举
   *
   * @param enumClass 枚举类
   * @param code 枚举码
   * @param <T> 类型
   * @return 解析枚举值 返回枚举
   */
  static <T extends Enum<T> & EnumInterface> T fromCode(Class<T> enumClass, Integer code) {
    return fromPredicateElse(enumClass, codePredicate(code), null);
  }

  /**
   * 解析枚举值 返回枚举
   *
   * @param enumClass 枚举类
   * @param code 枚举码
   * @param <T> 类型
   * @param errorCode 错误码
   * @return 解析枚举值 返回枚举
   */
  static <T extends Enum<T> & EnumInterface> T fromCodeThrow(
      Class<T> enumClass, Integer code, ErrorCodeInterface errorCode) {
    return fromCodeThrow(enumClass, code, new ApiException(errorCode));
  }

  /**
   * 解析枚举值 返回枚举
   *
   * @param enumClass 枚举类
   * @param code 枚举码
   * @param <T> 类型
   * @param ex 运行时异常
   * @return 解析枚举值 返回枚举
   */
  static <T extends Enum<T> & EnumInterface> T fromCodeThrow(
      Class<T> enumClass, Integer code, RuntimeException ex) {
    return fromPredicateThrow(enumClass, codePredicate(code), ex);
  }

  /**
   * 解析枚举值 返回枚举
   *
   * @param enumClass 枚举类
   * @param code 枚举码
   * @param <T> 类型
   * @param ex 异常
   * @return 解析枚举值 返回枚举
   */
  static <T extends Enum<T> & EnumInterface> T fromCodeThrow(
      Class<T> enumClass, Integer code, Exception ex) {
    return fromPredicateThrow(enumClass, e -> Objects.equals(e.getCode(), code), ex);
  }

  static <T extends Enum<T> & EnumInterface> T fromDesc(Class<T> enumClass, String desc) {
    return fromPredicateElse(enumClass, descPredicate(desc), null);
  }

  static <T extends Enum<T> & EnumInterface> T fromDescElse(
      Class<T> enumClass, String desc, T other) {
    return fromPredicateElse(enumClass, descPredicate(desc), other);
  }

  static <T extends Enum<T> & EnumInterface> T fromDescThrow(Class<T> enumClass, String desc) {
    return fromDescThrow(enumClass, desc, ErrorCode.Business.COMMON_UNSUPPORTED_OPERATION);
  }

  static <T extends Enum<T> & EnumInterface> T fromDescThrow(
      Class<T> enumClass, String desc, ErrorCodeInterface errorCode) {
    return fromPredicateThrow(enumClass, descPredicate(desc), new ApiException(errorCode));
  }

  static <T extends Enum<T> & EnumInterface> T fromName(Class<T> enumClass, String name) {
    return fromPredicateElse(enumClass, namePredicate(name), null);
  }

  static <T extends Enum<T> & EnumInterface> T fromNameElse(
      Class<T> enumClass, String name, T other) {
    return fromPredicateElse(enumClass, namePredicate(name), other);
  }

  static <T extends Enum<T> & EnumInterface> T fromNameThrow(Class<T> enumClass, String name) {
    return fromNameThrow(enumClass, name, ErrorCode.Business.COMMON_UNSUPPORTED_OPERATION);
  }

  static <T extends Enum<T> & EnumInterface> T fromNameThrow(
      Class<T> enumClass, String name, ErrorCodeInterface errorCode) {
    return fromNameThrow(enumClass, name, new ApiException(errorCode));
  }

  static <T extends Enum<T> & EnumInterface> T fromNameThrow(
      Class<T> enumClass, String name, RuntimeException ex) {
    return fromPredicateThrow(enumClass, namePredicate(name), ex);
  }

  static <T extends Enum<T> & EnumInterface> T fromPredicateThrow(
      Class<T> enumClass, Predicate<? super T> predicate) {
    return fromPredicateThrow(
        enumClass, predicate, ErrorCode.Business.COMMON_UNSUPPORTED_OPERATION);
  }

  static <T extends Enum<T> & EnumInterface> T fromPredicateThrow(
      Class<T> enumClass, Predicate<? super T> predicate, ErrorCodeInterface errorCode) {
    return fromPredicateThrow(enumClass, predicate, new ApiException(errorCode));
  }

  static <T extends Enum<T> & EnumInterface> T fromPredicateThrow(
      Class<T> enumClass, Predicate<? super T> predicate, Exception ex) {
    try {
      return Arrays.stream(enumClass.getEnumConstants())
          .filter(predicate)
          .findFirst()
          .orElseThrow(() -> ex);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  static <T extends Enum<T> & EnumInterface> T fromPredicateThrow(
      Class<T> enumClass, Predicate<? super T> predicate, RuntimeException ex) {
    return Arrays.stream(enumClass.getEnumConstants())
        .filter(predicate)
        .findFirst()
        .orElseThrow(() -> ex);
  }

  static <T extends Enum<T> & EnumInterface> T fromPredicateElse(
      Class<T> enumClass, Predicate<? super T> predicate, T other) {
    return Arrays.stream(enumClass.getEnumConstants()).filter(predicate).findFirst().orElse(other);
  }

  static <T extends Enum<T> & EnumInterface> Predicate<T> codePredicate(Integer code) {
    return e -> Objects.equals(e.getCode(), code);
  }

  static <T extends Enum<T> & EnumInterface> Predicate<T> descPredicate(String desc) {
    return e -> StrUtil.equals(e.getDesc(), desc);
  }

  static <T extends Enum<T> & EnumInterface> Predicate<T> namePredicate(String name) {
    return e -> StrUtil.equals(e.name(), name);
  }

  /**
   * 枚举值
   *
   * @return 枚举值
   */
  int getCode();

  /**
   * 获取描述
   *
   * @return 获取描述
   */
  String getDesc();
}
